﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace LTorrent.Extensions
{
    public static class Extensions
    {
        //Перевод числа в BigEndian байты
        public static Byte[] toNetworkOrder(this UInt32 a)
        {
            return new Byte[] { (Byte)((a & 0xff000000) >> 24), 
                                (Byte)((a & 0x00ff0000) >> 16), 
                                (Byte)((a & 0x0000ff00) >> 8), 
                                (Byte)((a & 0x000000ff)) 
                            };
        }

        //Перевод BigEndian байт в число
        public static UInt32 fromNetworkOrder(this Byte[] a)
        {
            if (a.Length < 4)
                throw new ArgumentException("Length must be 4! (fromNetworkOrder Method)");
            return (UInt32)(((UInt32)(a[0]) << 24) 
                | ((UInt32)(a[1]) << 16) 
                | ((UInt32)(a[2]) << 8) 
                | ((UInt32)(a[3])) );
        }

        //Добавляет полученный индекс. (используется в Extended peers и Caller классах. Have сообщения)
        //Value = 1 - выдается метка занят и value = 0 - освобожден
        public static void addPiece(this Byte[] a, UInt32 Index, Byte Value = 1)
        {
            if (Index > a.Length * 8) return;

            UInt32 Offset = Index / 8;
            Index = 7 - Index % 8;
            a[Offset] = (Byte)(a[Offset] | ((Byte)(Value << ((int)Index))));

        }

        /// <summary>
        /// Подготовка потока.
        /// Необходимо по причине неверной обработки потока с помощью BinaryReader - Peek возвращает некорректный результат
        /// </summary>
        public static Stream PreparedStream(this Stream mStr)
        {
            if (mStr == null)
                throw new ArgumentNullException("Incorrect tracker answer!");
            var X = new MemoryStream();
            mStr.CopyTo(X);
            X.Seek(0, SeekOrigin.Begin);
            return X;
        }
        public static string ConvertIPV4BytesToStringValue(this byte[] input, bool NetWorkOrder = true)
        {//Получаем IP по массиву байтов 
            if (input == null || input.Length != 4)
                throw new ArgumentException("Неверный вызов параметров преобразования IP адреса");
            UInt32 IP = 0;
            int direction;
            int i;

            if (NetWorkOrder)
            {//выбор направления
                direction = 1;
                i = 0;
            }
            else
            {
                direction = -1;
                i = input.Length - 1;
            }

            for (; i >= 0 && i < input.Length; i += direction)
            {//перевод в одно число массив
                IP = ((IP << 8) | input[i]);
            }
            //127.0.0.1 формат 
            return string.Format("{0}.{1}.{2}.{3}",
                ((IP & 0xff000000) >> 24),
                ((IP & 0x00ff0000) >> 16),
                ((IP & 0x0000ff00) >> 8),
                ((IP & 0x000000ff))
                );

        }

        public static int ConvertPortBytesToInt32Value(this byte[] Port, bool isNetworkOrder = true)
        {//Создание порта по байтам
            int ResPort = 0;

            if (isNetworkOrder)
                for (int i = 0; i < Port.Length; i++)
                    ResPort = ((ResPort << 8) | Port[i]);
            else
                for (int i = Port.Length - 1; i >= 0; i--)
                    ResPort = ((ResPort << 8) | Port[i]);

            return ResPort;
        }
    }
}
